import wx
import os
import subprocess
import json
import platform
from pathlib import Path

class CommandManager(wx.Frame):
    def __init__(self):
        super().__init__(None, title="终端命令管理器", size=(1000, 600))
        
        self.command_data = []
        self.config_file = "command_manager_config.json"
        
        self.init_ui()
        self.load_config()
        self.CenterOnScreen()
        
    def init_ui(self):
        panel = wx.Panel(self)
        
        # 主布局
        main_sizer = wx.BoxSizer(wx.VERTICAL)
        
        # 工具栏
        toolbar = wx.ToolBar(panel, style=wx.TB_TEXT | wx.TB_HORIZONTAL | wx.TB_HORZ_LAYOUT)
        toolbar.AddTool(wx.ID_ADD, "添加", wx.ArtProvider.GetBitmap(wx.ART_PLUS))
        toolbar.AddTool(wx.ID_DELETE, "删除", wx.ArtProvider.GetBitmap(wx.ART_MINUS))
        toolbar.AddTool(wx.ID_SAVE, "保存", wx.ArtProvider.GetBitmap(wx.ART_FILE_SAVE))
        toolbar.AddSeparator()
        toolbar.AddTool(wx.ID_EXECUTE, "运行", wx.ArtProvider.GetBitmap(wx.ART_GO_FORWARD))
        toolbar.Realize()
        
        # 绑定工具栏事件
        toolbar.Bind(wx.EVT_TOOL, self.on_add_command, id=wx.ID_ADD)
        toolbar.Bind(wx.EVT_TOOL, self.on_delete_command, id=wx.ID_DELETE)
        toolbar.Bind(wx.EVT_TOOL, self.on_save, id=wx.ID_SAVE)
        toolbar.Bind(wx.EVT_TOOL, self.on_run_selected_command, id=wx.ID_EXECUTE)
        
        main_sizer.Add(toolbar, 0, wx.EXPAND)
        
        # 搜索框
        search_box = wx.BoxSizer(wx.HORIZONTAL)
        search_label = wx.StaticText(panel, label="搜索:")
        self.search_ctrl = wx.SearchCtrl(panel)
        self.search_ctrl.Bind(wx.EVT_TEXT, self.on_search)
        search_box.Add(search_label, 0, wx.ALIGN_CENTER_VERTICAL|wx.RIGHT, 5)
        search_box.Add(self.search_ctrl, 1, wx.EXPAND)
        main_sizer.Add(search_box, 0, wx.EXPAND|wx.ALL, 5)
        
        # 命令列表
        self.list_ctrl = wx.ListCtrl(panel, style=wx.LC_REPORT|wx.LC_SINGLE_SEL|wx.BORDER_SUNKEN)
        self.list_ctrl.InsertColumn(0, "#", width=50)  # 行号列
        self.list_ctrl.InsertColumn(1, "命令名称", width=150)
        self.list_ctrl.InsertColumn(2, "实际命令", width=400)
        self.list_ctrl.InsertColumn(3, "备注", width=300)
        
        main_sizer.Add(self.list_ctrl, 1, wx.EXPAND|wx.ALL, 5)
        
        panel.SetSizer(main_sizer)
        
        # 绑定事件
        self.list_ctrl.Bind(wx.EVT_LIST_ITEM_SELECTED, self.on_item_selected)
        self.list_ctrl.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.on_item_activated)
        
        # 状态栏
        self.CreateStatusBar()
        
    def load_config(self):
        if os.path.exists(self.config_file):
            try:
                with open(self.config_file, 'r', encoding='utf-8') as f:
                    self.command_data = json.load(f)
                self.update_list()
            except Exception as e:
                wx.MessageBox(f"加载配置文件失败: {str(e)}", "错误", wx.OK|wx.ICON_ERROR)
    
    def save_config(self):
        try:
            with open(self.config_file, 'w', encoding='utf-8') as f:
                json.dump(self.command_data, f, indent=4, ensure_ascii=False)
            return True
        except Exception as e:
            wx.MessageBox(f"保存配置文件失败: {str(e)}", "错误", wx.OK|wx.ICON_ERROR)
            return False
    
    def update_list(self, filter_text=None):
        # 清空现有列表
        self.list_ctrl.DeleteAllItems()
        
        display_row_num = 0  # 显示的行号从1开始
        for idx, command in enumerate(self.command_data):
            name = command.get('name', '')
            cmd = command.get('command', '')
            note = command.get('note', '')
            
            # 过滤 - 现在会同时搜索名称、备注和实际命令
            if filter_text:
                filter_text_lower = filter_text.lower()
                if (filter_text_lower not in name.lower() and 
                    filter_text_lower not in note.lower() and 
                    filter_text_lower not in cmd.lower()):
                    continue
            
            display_row_num += 1  # 只有通过过滤的行才计数
            index = self.list_ctrl.InsertItem(idx, str(display_row_num))  # 显示连续行号
            self.list_ctrl.SetItem(index, 1, name)                        # 第1列：命令名称
            self.list_ctrl.SetItem(index, 2, cmd)                         # 第2列：实际命令
            self.list_ctrl.SetItem(index, 3, note)                        # 第3列：备注
            
    def on_add_command(self, event):
        dlg = CommandDialog(self, "添加命令")
        if dlg.ShowModal() == wx.ID_OK:
            command_info = {
                'name': dlg.name_ctrl.GetValue(),
                'command': dlg.command_ctrl.GetValue(),
                'note': dlg.note_ctrl.GetValue()
            }
            self.command_data.append(command_info)
            self.update_list()
            self.save_config()
        dlg.Destroy()
    
    def on_delete_command(self, event):
        selected = self.list_ctrl.GetFirstSelected()
        if selected != -1:
            # 获取要删除的命令名称用于提示
            command_name = self.command_data[selected].get('name', '未命名命令')
            
            # 添加确认对话框
            confirm_dlg = wx.MessageDialog(
                self,
                f"确定要删除命令 '{command_name}' 吗？",
                "确认删除",
                wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION
            )
            
            if confirm_dlg.ShowModal() == wx.ID_YES:
                self.command_data.pop(selected)
                self.update_list()
                self.save_config()
            
            confirm_dlg.Destroy()  # 必须销毁对话框
    
    def on_save(self, event):
        self.save_config()
    
    def on_search(self, event):
        filter_text = self.search_ctrl.GetValue()
        self.update_list(filter_text)
    
    def on_item_selected(self, event):
        pass
    
    def on_item_activated(self, event):
        selected = event.GetIndex()
        if selected != -1 and selected < len(self.command_data):
            command = self.command_data[selected]
            dlg = CommandDialog(self, "编辑命令")
            dlg.name_ctrl.SetValue(command.get('name', ''))
            dlg.command_ctrl.SetValue(command.get('command', ''))
            dlg.note_ctrl.SetValue(command.get('note', ''))
            
            if dlg.ShowModal() == wx.ID_OK:
                command['name'] = dlg.name_ctrl.GetValue()
                command['command'] = dlg.command_ctrl.GetValue()
                command['note'] = dlg.note_ctrl.GetValue()
                self.update_list()
                self.save_config()
            dlg.Destroy()
    
    def on_run_selected_command(self, event):
        selected = self.list_ctrl.GetFirstSelected()
        if selected != -1:
            self.run_command_by_index(selected)
        else:
            wx.MessageBox("请先选择一个命令", "提示", wx.OK|wx.ICON_INFORMATION)
    
    def run_command_by_index(self, command_idx):
        if command_idx < len(self.command_data):
            command = self.command_data[command_idx]
            cmd = command.get('command', '')
            
            if not cmd.strip():
                wx.MessageBox("命令为空", "错误", wx.OK|wx.ICON_ERROR)
                return
            
            try:
                # 根据操作系统选择shell
                shell = True
                if platform.system() == 'Windows':
                    cmd = f'cmd /c {cmd}'
                else:  # Linux/Mac
                    cmd = f'/bin/bash -c "{cmd}"'
                
                self.SetStatusText(f"执行命令: {cmd}")
                self.execute_command(cmd)
                
            except Exception as e:
                wx.MessageBox(f"执行命令失败: {str(e)}", "错误", wx.OK|wx.ICON_ERROR)
    
    def execute_command(self, cmd):
        # 创建一个新窗口来显示命令输出
        output_dlg = wx.Dialog(self, title="命令输出", size=(800, 600))
        
        output_text = wx.TextCtrl(output_dlg, style=wx.TE_MULTILINE|wx.TE_READONLY|wx.HSCROLL)
        output_text.SetFont(wx.Font(10, wx.FONTFAMILY_TELETYPE, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL))
        
        close_btn = wx.Button(output_dlg, wx.ID_CLOSE)
        
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(output_text, 1, wx.EXPAND|wx.ALL, 5)
        sizer.Add(close_btn, 0, wx.ALIGN_CENTER|wx.ALL, 5)
        
        output_dlg.SetSizer(sizer)
        
        close_btn.Bind(wx.EVT_BUTTON, lambda e: output_dlg.EndModal(wx.ID_OK))
        
        # 在新线程中执行命令
        import threading
        def run_command():
            process = subprocess.Popen(
                cmd, 
                shell=True, 
                stdout=subprocess.PIPE, 
                stderr=subprocess.STDOUT,
                universal_newlines=True,
                #encoding='utf-8',
                encoding='utf-8' if platform.system() != 'Windows' else 'gbk',  # 显式区分系统
                errors='replace'
            )
            
            for line in process.stdout:
                wx.CallAfter(output_text.AppendText, line)
            
            process.wait()
            wx.CallAfter(output_text.AppendText, f"\n\n命令执行完成，退出码: {process.returncode}")
        
        thread = threading.Thread(target=run_command)
        thread.daemon = True
        thread.start()
        
        output_dlg.ShowModal()
        output_dlg.Destroy()

class CommandDialog(wx.Dialog):
    def __init__(self, parent, title):
        super().__init__(parent, title=title, size=(600, 500), 
                         style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER)
        
        self.init_ui()
    
    def init_ui(self):
        panel = wx.Panel(self)
        
        # 表单布局
        form_sizer = wx.FlexGridSizer(3, 2, 10, 10)
        form_sizer.AddGrowableCol(1, 1)
        form_sizer.AddGrowableRow(1, 1)  # 让命令行可以扩展
        form_sizer.AddGrowableRow(2, 1)  # 让备注行可以扩展
        
        # 命令名称
        name_label = wx.StaticText(panel, label="命令名称:")
        self.name_ctrl = wx.TextCtrl(panel)
        form_sizer.Add(name_label, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT)
        form_sizer.Add(self.name_ctrl, 1, wx.EXPAND)
        
        # 实际命令（多行文本框）
        command_label = wx.StaticText(panel, label="实际命令:")
        self.command_ctrl = wx.TextCtrl(panel, style=wx.TE_MULTILINE)
        form_sizer.Add(command_label, 0, wx.ALIGN_TOP|wx.ALIGN_RIGHT)
        form_sizer.Add(self.command_ctrl, 1, wx.EXPAND)
        
        # 备注（多行文本框）
        note_label = wx.StaticText(panel, label="备注:")
        self.note_ctrl = wx.TextCtrl(panel, style=wx.TE_MULTILINE)
        form_sizer.Add(note_label, 0, wx.ALIGN_TOP|wx.ALIGN_RIGHT)
        form_sizer.Add(self.note_ctrl, 1, wx.EXPAND)
        
        # 按钮
        btn_sizer = wx.StdDialogButtonSizer()
        ok_btn = wx.Button(panel, wx.ID_OK)
        cancel_btn = wx.Button(panel, wx.ID_CANCEL)
        btn_sizer.AddButton(ok_btn)
        btn_sizer.AddButton(cancel_btn)
        btn_sizer.Realize()
        
        # 主布局
        main_sizer = wx.BoxSizer(wx.VERTICAL)
        main_sizer.Add(form_sizer, 1, wx.EXPAND|wx.ALL, 10)
        main_sizer.Add(btn_sizer, 0, wx.ALIGN_CENTER|wx.BOTTOM, 10)
        
        panel.SetSizer(main_sizer)
        
        # 设置最小大小
        self.SetMinSize(wx.Size(500, 400))
        
        # 绑定窗口大小变化事件
        self.Bind(wx.EVT_SIZE, self.on_size)
    
    def on_size(self, event):
        # 确保布局正确调整
        self.Layout()
        event.Skip()

if __name__ == "__main__":
    app = wx.App(False)
    frame = CommandManager()
    frame.Show()
    app.MainLoop()